//    Copyright (C) Kherty.  All rights reserved.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Media;
using OpenLS.Core.Formatting;

namespace OpenLS.Core
{
    class FormatClause
    {
        FormatClause(Format owner)
        {
            Owner = owner;
        }
        public bool Matches(double d)
        {
            return predicate(d);
        }
        private Predicate<double> predicate;

        public Predicate<double> Predicate
        {
            get { return predicate; }
            set { predicate = value; }
        }

        readonly List<FormatItem> formats = new List<FormatItem>();
        internal Color? color;
        internal bool suppressMinus;
        bool elapsedTime;
        readonly Format Owner;
        internal static FormatClause Create(Format owner, List<FormatToken> tokens)
        {
            FormatClause result = new FormatClause(owner);
            foreach (FormatToken token in tokens)
            {
                if (token is ClauseFormatToken)
                {
                    ((ClauseFormatToken)token).Apply(result);
                    continue;
                }
               // Core.Format.Warn();
            }
            
            return result;
        }

        internal static FormatClause Parse(Format owner, string s)
        {
            FormatClause result = new FormatClause(owner);
            if (s[0] == '[')
            {
                int endIndex = s.IndexOf(']', 1);
                if (endIndex > 1)
                {
                    string prefix = s.Substring(0, endIndex + 1);
                    string innerPrefix = prefix.Substring(1, prefix.Length - 2);
                    switch (innerPrefix.ToLower())
                    {
                        case "h":
                        case "m":
                        case "s":
                            result.elapsedTime = true; break;
                        default:
                            switch (innerPrefix.ToLower())
                            {
                                case "red": result.color = Colors.Red; break;
                                case "black": result.color = Colors.Black; break;
                                case "blue": result.color = Colors.Blue; break;
                                case "cyan": result.color = Colors.Cyan; break;
                                case "green": result.color = Colors.Green; break;
                                case "magenta": result.color = Colors.Magenta; break;
                                case "white": result.color = Colors.White; break;
                                case "yellow": result.color = Colors.Yellow; break;
                                case "mm": break;//\\
                                case "ss": break;//\\
                                default:
                                    Debug.WriteLine("not implemented" + innerPrefix);//\\throw new NotImplementedException();
                                    break;
                            }
                            break;
                    }
                    s = s.Substring(prefix.Length, s.Length - prefix.Length);
                }
                else
                    throw new NotSupportedException();
            }
            s = s.Replace("[$$-409]", "$");//\\
            result.SetFormats(s);
            return result;
        }

        private void SetFormats(string s)
        {
            string[] ss = s.Split('_'); //\\
            if (ss[0].Length > 0)
                formats.Add(new StandardFormatItem(ss[0]));
            foreach (string si in ss)
            {
                if (si == ss[0])
                    continue;
                formats.Add(new InvisibleTextFormatItem(si[0].ToString()));
                if (si.Length - 1 > 0)
                    formats.Add(new StandardFormatItem(si.Substring(1, si.Length - 1)));
            }
        }

        internal object Format(double d)
        {
            if (suppressMinus)
                d = -d;
            if (formats.Count == 1)
                return formats[0].Format(d);
            List<object> result = new List<object>();
            foreach (FormatItem i in formats)
                result.Add(i.Format(d));
            return new CompositeFormattedValue(result);
        }

        internal void Adjust()
        {
            switch (Index)
            {
                case 0:
                    switch (Owner.Clauses.Count)
                    {
                        case 1:
                            Predicate = delegate { return true; }; break;
                        case 2:
                            Predicate = delegate(double d) { return d >= 0; }; break;
                        default:
                            Predicate = delegate(double d) { return d > 0; };
                            break;
                    } break;
                case 1:
                    suppressMinus = true;
                    if (Owner.Clauses.Count == 2)
                        Predicate = delegate { return true; };
                    else
                        Predicate = delegate(double d) { return d < 0; }; break;
                case 2:
                    Predicate = delegate(double d) { return d == 0; }; break;
                case 3:
                    Predicate = delegate { return true; }; break;
            }
        }

        int Index { get { return Owner.Clauses.IndexOf(this); } }

        public bool ElapsedTime
        {
            get { return elapsedTime; }
        }

        internal void AddStandardFormatItem(string Code)
        {
            if (formats.Count == 0 || !(formats[formats.Count - 1] is StandardFormatItem))
            {
                formats.Add(new StandardFormatItem(Code));
                return;
            }
            StandardFormatItem i = (StandardFormatItem) formats[formats.Count - 1];
            i.format += Code;
        }

        internal void AddInvisibleFormatItem(string p)
        {
            formats.Add(new InvisibleTextFormatItem(p));
        }
        internal void AddRepeatFormatItem(char c)
        {
            formats.Add(new RepeatTextFormatItem(c));
        }
    }
}
